open Common
open Gtk

class mainWindow () =
	let create_column_list() =
		let l = new GTree.column_list in
		let id = l#add Gobject.Data.int64 in
		let title = l#add Gobject.Data.string in
		let year = l#add Gobject.Data.uint in
			(l, id, title, year)
	and ret p =	fun () -> p
	and not_initialized =	fun () -> failwith "Not initilized"
	in
object(self)
	val _wnd = GWindow.window ();
	val _addDlg = new AddMovieDlgUI.addMovieDlg ()
		
	val mutable _tb = not_initialized
	val mutable _addBtn = not_initialized
	val mutable _changeBtn = not_initialized
	val mutable _deleteBtn = not_initialized
	val mutable _titleView = not_initialized
	val mutable _imageWnd = not_initialized
	val mutable _descrView = not_initialized
		
	val _columns = create_column_list()
	method private _columnsList = match _columns with l, _, _, _ -> l
	method private _idColumn = match _columns with _, id, _, _ -> id
	method private _titleColumn = match _columns with _, _, title, _ -> title
	method private _yearColumn = match _columns with _, _, _, year -> year

	val mutable _model = None
	val mutable _catalog = None

	val _onSelectedTitleChanged = new Events.event ()
	method private emit_selection_changed l =
		_onSelectedTitleChanged#emit (Events.emtr l)
		
	method private init_model () =
		_model <- Some(GTree.list_store self#_columnsList)
			
	method private init_toolbar () =
		let toolbar = GButton.toolbar ~style:`ICONS	~tooltips:false () in
		let addBtn = toolbar#insert_button ~icon:(GMisc.image ~stock:`ADD ())#coerce ()
		and changeBtn = toolbar#insert_button ~icon:(GMisc.image ~stock:`EDIT ())#coerce ()
		and deleteBtn = toolbar#insert_button ~icon:(GMisc.image ~stock:`DELETE ())#coerce ()
		in
			_tb <- ret toolbar;
			_addBtn <- ret addBtn;
			_changeBtn <- ret changeBtn;
			_deleteBtn <- ret deleteBtn;
			toolbar

	method private init_titles_view () =
		let sc_win = GBin.scrolled_window
			~shadow_type:`IN
			~hpolicy:`AUTOMATIC
			~vpolicy:`AUTOMATIC
			()
		in
		let create_view_column ~title data_col =
			let renderer = GTree.cell_renderer_text [] in
			let col = GTree.view_column ~title ~renderer:(renderer, ["text", data_col]) () in
				col
		in
		let view = GTree.view ~packing:sc_win#add () in
			view#selection#set_mode `BROWSE;
			view#append_column (create_view_column ~title:"Title" self#_titleColumn) |> ignore;
			view#append_column (create_view_column ~title:"Year" self#_yearColumn) |> ignore;

			view#selection#connect#changed ~callback:(
				fun () ->
					self#get_selected_ids() |> self#emit_selection_changed
			) |> ignore;
			
			_titleView <- ret view;
			sc_win

	method private init_text_view () =
		let expander = GBin.expander ~label:"Description" ~border_width:3 ()
		and sc_win = GBin.scrolled_window
			~shadow_type:`ETCHED_IN
			~hpolicy:`NEVER
			~vpolicy:`AUTOMATIC
			()
		and textView = GText.view ~editable:false ()
		(* and titleSelectionChangedHandler l = *)
		(* 	let textBuffer = (_descrView())#buffer in *)
		(* 		match l with *)
		(* 			| id :: [] -> *)
		(* 					let movie = (Option.get _catalog)#item id in *)
		(* 						textBuffer#set_text (movie#desc) *)
			(* 			| _ -> textBuffer#set_text "" *)
		and titleSelectionChangedHandler l =
			()
		in
			expander#add sc_win#coerce;
			sc_win#add textView#coerce;
			_descrView <- ret textView;
			_onSelectedTitleChanged#connect titleSelectionChangedHandler |> ignore;
			expander
		
	method private init_image_window () =
	  let imgWin = GMisc.image () in
		_imageWnd <- ret imgWin;
		(* let pixBuf = GdkPixbuf.from_file_at_size "test.png" 266 200 in *)
		(*   (_imageWnd())#set_pixbuf pixBuf; *)
		  imgWin
				
	method private init_main_window wnd =
		wnd#set_default_size ~width:200 ~height:200;
		let top_vbox = GPack.vbox()
		and workingArea = GPack.paned `HORIZONTAL ()
		and rightFrame = GBin.frame ()
		and rightVbox = GPack.vbox ()
		and textExpander = self#init_text_view() in
			wnd#add top_vbox#coerce;
			top_vbox#pack (self#init_toolbar())#coerce;
			top_vbox#pack ~expand:true workingArea#coerce;

			workingArea#pack1 (self#init_titles_view())#coerce;
			workingArea#pack2 ~resize:true ~shrink:false rightFrame#coerce;
			
			rightFrame#add rightVbox#coerce;
			rightVbox#pack ~expand:true ~fill:false (self#init_image_window())#coerce;
			rightVbox#pack ~expand:false ~fill:false textExpander#coerce;
			
			GtkSignal.connect_by_name textExpander#as_widget
				~name:"notify::expanded"
				~callback:(Gobject.Closure.create
										 (fun _ ->
												let expanded = textExpander#expanded in
													rightVbox#misc#hide();
													rightVbox#set_child_packing ~expand:(not expanded) ~fill:false (_imageWnd())#coerce;
													rightVbox#set_child_packing ~expand:expanded ~fill:expanded textExpander#coerce;
													rightVbox#misc#show()
										 ))
				~after:false |> ignore;
			_onSelectedTitleChanged#connect
				(fun _ ->
					 let str = Printf.sprintf "%s: x = %d, y = %d, w = %d, h = %d\n" in
					 let rect_to_str w n =
					 	 let rect = w#misc#allocation in
					 		 str n rect.x rect.y rect.width rect.height
					 in
					 	 (_descrView())#buffer#insert (rect_to_str rightFrame "rightFrame");
					 	 (_descrView())#buffer#insert (rect_to_str rightVbox "rightVbox");
					 	 (_descrView())#buffer#insert (rect_to_str textExpander "textExpander")
				) |> ignore

	method private attach_model_to_view () =
		(_titleView())#set_model (_model :> GTree.model option)

	method private dettach_model_from_view () =
		(_titleView())#set_model None;
		Option.get _model

	method private add_movie_to_model (model:GTree.list_store) movie =
		let newRow = model#append () in
			model#set ~row:newRow ~column:self#_idColumn movie#id;
			model#set ~row:newRow ~column:self#_titleColumn movie#title;
			model#set ~row:newRow ~column:self#_yearColumn movie#year
				
	method private fill_model_from_catalog (c : MCol.moviesCollection option) =
		let model = self#dettach_model_from_view () in
			model#clear();
			Option.may (fun c -> List.iter (self#add_movie_to_model model) c#items) c;
			self#attach_model_to_view()

	method private get_selected_ids () =
		let get_id_of_row row idsList =
			((Option.get _model)#get ~row:((Option.get _model)#get_iter row) ~column:self#_idColumn) :: idsList
		in
			List.fold_right get_id_of_row (_titleView())#selection#get_selected_rows []

	(* Catalog event handlers *)
	method private on_movie_delete movie =
		let m = Option.get _model in
		let rec process_iter iter =
			let curId = m#get ~row:iter ~column:self#_idColumn in
				if curId = movie#id then (
					m#remove iter |> ignore
				) else (
					if m#iter_next iter then process_iter iter
				)
		in
			Option.may process_iter m#get_iter_first
			
	method private on_movie_add m =
		self#add_movie_to_model (Option.get _model) m

	(* Catalog event handlers ends here *)
			
	initializer
		self#init_model();
		self#init_main_window _wnd;
		(_addBtn())#connect#clicked
			~callback:(
				fun () ->
					Option.may
						(fun newMovie -> Option.may (fun catalog -> catalog#add_movie newMovie) _catalog)
						(_addDlg#run None))
		|> ignore;

		(_deleteBtn())#connect#clicked
			~callback:(
				fun () ->
					Option.may
						(fun catalog -> self#get_selected_ids () |> List.iter catalog#remove_movie)
						_catalog)
		|> ignore
	
	method attach_catalog (c : MCol.moviesCollection option) =
		_catalog <- c;
		self#fill_model_from_catalog _catalog;
		Option.may (fun c ->
									c#on_remove#connect self#on_movie_delete |> ignore;
									c#on_add#connect self#on_movie_add |> ignore
							 ) c

	method run () =
		_wnd#connect#destroy ~callback:GMain.Main.quit |> ignore;
		_wnd#show ();
		GMain.Main.main()
end

(* let create_menu ~packing = *)
(* 	let menu_bar = GMenu.menu_bar ~packing () in *)
(* 	let file_item = GMenu.menu_item ~label:"File" ~packing:menu_bar#append () in *)
(* 	let file_menu = GMenu.menu ~packing:file_item#set_submenu () in *)
(* 	let insert_item (name, callback) = *)
(* 		let item = GMenu.menu_item ~label:name ~packing:file_menu#append () in *)
(* 			ignore (item#connect#activate ~callback) *)
(* 	in *)
(* 	let foo () = () in *)
(* 		List.iter insert_item [("New", foo); ("Open", foo); ("Save", foo); ("Quit", foo)]; *)
(* 		() *)
